#include <iostream>
#include <conio.h>
#include <windows.h>
#include <vector>
#include <ctime>
#include <cstdlib>
#include <fstream>

using namespace std;

// 游戏区域大小
const int WIDTH = 40;
const int HEIGHT = 20;

// 方向枚举
enum Direction { STOP = 0, LEFT, RIGHT, UP, DOWN };

// 坐标结构体
struct Point {
    int x, y;
    Point(int x = 0, int y = 0) : x(x), y(y) {}
    bool operator==(const Point& p) const {
        return x == p.x && y == p.y;
    }
};

// 设置控制台光标位置
void gotoxy(int x, int y) {
    COORD pos;
    pos.X = x;
    pos.Y = y;
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}

// 设置文本颜色
void setColor(int color) {
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color);
}

// 隐藏光标
void hideCursor() {
    CONSOLE_CURSOR_INFO cursor_info = {1, 0};
    SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);
}

// 游戏类
class Game {
private:
    bool gameOver;
    bool win;
    int score;
    int highScore;
    Point food;
    vector<Point> snake;
    Direction dir;
    int sleepTime; // 控制游戏速度的时间间隔
    
    // 从文件中读取最高分
    void File_out() {
        ifstream file("save.txt");
        if (file.is_open()) {
            file >> highScore;
            file.close();
        } else {
            highScore = 0;
        }
    }
    
    // 将最高分写入文件
    void File_in() {
        ofstream file("save.txt");
        if (file.is_open()) {
            file << highScore;
            file.close();
        }
    }
    
    // 创建游戏地图
    void createMap() {
        system("cls");
        
        // 绘制上边界
        for (int i = 0; i < WIDTH + 2; i++)
            cout << "#";
        cout << endl;
        
        // 绘制游戏区域
        for (int i = 0; i < HEIGHT; i++) {
            for (int j = 0; j < WIDTH; j++) {
                if (j == 0)
                    cout << "#"; // 左边界
                else if (j == WIDTH - 1)
                    cout << "#"; // 右边界
                else
                    cout << " ";
            }
            cout << endl;
        }
        
        // 绘制下边界
        for (int i = 0; i < WIDTH + 2; i++)
            cout << "#";
        cout << endl;
    }
    
    // 显示得分和提示信息
    void scoreAndTips() {
        gotoxy(WIDTH + 5, 2);
        cout << "得分: " << score;
        gotoxy(WIDTH + 5, 4);
        cout << "最高分: " << highScore;
        gotoxy(WIDTH + 5, 6);
        cout << "操作说明:";
        gotoxy(WIDTH + 5, 7);
        cout << "↑ ↓ ← → : 控制方向";
        gotoxy(WIDTH + 5, 8);
        cout << "F1: 加速";
        gotoxy(WIDTH + 5, 9);
        cout << "F2: 减速";
        gotoxy(WIDTH + 5, 10);
        cout << "ESC: 退出游戏";
    }
    
    // 初始化蛇身体
    void initSnake() {
        snake.clear();
        // 初始蛇尾位置
        int tailX = 24;
        int tailY = 5;
        
        // 创建初始蛇身（5节）
        for (int i = 0; i < 5; i++) {
            snake.push_back(Point(tailX + 2 * (4 - i), tailY));
        }
        
        // 设置初始方向
        dir = LEFT;
    }
    
    // 创建食物
    void createFood() {
        bool validPosition;
        do {
            validPosition = true;
            // 确保食物在地图内部，不在边界上
            food.x = 1 + rand() % (WIDTH - 2);
            food.y = 1 + rand() % (HEIGHT - 2);
            
            // 确保食物不会生成在蛇身上
            for (const auto& p : snake) {
                if (food.x == p.x && food.y == p.y) {
                    validPosition = false;
                    break;
                }
            }
        } while (!validPosition);
        
        // 绘制食物
        gotoxy(food.x + 1, food.y + 1); // +1是因为边界
        setColor(12); // 红色
        cout << "*";
        setColor(7); // 恢复默认颜色
    }
    
    // 绘制蛇
    void drawSnake() {
        for (size_t i = 0; i < snake.size(); i++) {
            gotoxy(snake[i].x + 1, snake[i].y + 1); // +1是因为边界
            
            if (i == 0) {
                setColor(10); // 绿色蛇头
                cout << "@";
            } else {
                setColor(14); // 黄色蛇身
                cout << "★";
            }
        }
        setColor(7); // 恢复默认颜色
    }
    
    // 判断蛇是否咬到自己
    bool biteSelf() {
        for (size_t i = 1; i < snake.size(); i++) {
            if (snake[0].x == snake[i].x && snake[0].y == snake[i].y) {
                return true;
            }
        }
        return false;
    }
    
    // 判断蛇是否撞墙
    bool cantCrossWall() {
        if (snake[0].x < 0 || snake[0].x >= WIDTH - 1 || snake[0].y < 0 || snake[0].y >= HEIGHT) {
            return true;
        }
        return false;
    }
    
    // 蛇加速
    void speedUp() {
        if (sleepTime >= 50) {
            sleepTime -= 10;
        }
    }
    
    // 蛇减速
    void speedDown() {
        if (sleepTime <= 320) {
            sleepTime += 30;
        }
    }
    
    // 蛇移动
    void snakeMove() {
        // 清除蛇尾
        gotoxy(snake.back().x + 1, snake.back().y + 1);
        cout << " ";
        
        // 移动蛇身
        for (size_t i = snake.size() - 1; i > 0; i--) {
            snake[i] = snake[i - 1];
        }
        
        // 移动蛇头
        switch (dir) {
            case LEFT:
                snake[0].x--;
                break;
            case RIGHT:
                snake[0].x++;
                break;
            case UP:
                snake[0].y--;
                break;
            case DOWN:
                snake[0].y++;
                break;
            default:
                break;
        }
        
        // 绘制新的蛇头
        gotoxy(snake[0].x + 1, snake[0].y + 1);
        setColor(10);
        cout << "@";
        
        // 绘制第一节蛇身
        if (snake.size() > 1) {
            gotoxy(snake[1].x + 1, snake[1].y + 1);
            setColor(14);
            cout << "★";
        }
        
        setColor(7); // 恢复默认颜色
        
        // 检查是否吃到食物
        if (snake[0].x == food.x && snake[0].y == food.y) {
            // 增加蛇长度
            snake.push_back(snake.back());
            
            // 增加分数
            if (sleepTime <= 320) {
                score += 2;
            } else {
                score += 1;
            }
            
            // 更新最高分
            if (score > highScore) {
                highScore = score;
                File_in(); // 保存新的最高分
            }
            
            // 更新得分显示
            gotoxy(WIDTH + 5, 2);
            cout << "得分: " << score;
            gotoxy(WIDTH + 5, 4);
            cout << "最高分: " << highScore;
            
            // 创建新食物
            createFood();
        }
    }
    
    // 键盘控制
    void keyboardControl() {
        // 检查按键
        if (GetAsyncKeyState(VK_UP) && dir != DOWN) {
            dir = UP;
        } else if (GetAsyncKeyState(VK_DOWN) && dir != UP) {
            dir = DOWN;
        } else if (GetAsyncKeyState(VK_LEFT) && dir != RIGHT) {
            dir = LEFT;
        } else if (GetAsyncKeyState(VK_RIGHT) && dir != LEFT) {
            dir = RIGHT;
        } else if (GetAsyncKeyState(VK_F1)) {
            speedUp();
        } else if (GetAsyncKeyState(VK_F2)) {
            speedDown();
        } else if (GetAsyncKeyState(VK_ESCAPE)) {
            gameOver = true;
        }
    }
    
    // 游戏失败界面
    void gameOverScreen() {
        system("cls");
        gotoxy(WIDTH / 2 - 5, HEIGHT / 2 - 2);
        cout << "游戏结束！";
        gotoxy(WIDTH / 2 - 10, HEIGHT / 2);
        cout << "你的得分: " << score;
        
        if (score >= highScore) {
            gotoxy(WIDTH / 2 - 15, HEIGHT / 2 + 1);
            cout << "创纪录啦！最高分被你刷新啦，真棒！！！";
        } else {
            gotoxy(WIDTH / 2 - 15, HEIGHT / 2 + 1);
            cout << "继续努力吧~你离最高分还差: " << highScore - score << " 分";
        }
        
        gotoxy(WIDTH / 2 - 10, HEIGHT / 2 + 3);
        cout << "1: 重玩  2: 退出游戏";
        
        char choice;
        while (true) {
            choice = _getch();
            if (choice == '1') {
                // 重新开始游戏
                gameOver = false;
                score = 0;
                sleepTime = 200;
                initSnake();
                createMap();
                scoreAndTips();
                createFood();
                drawSnake();
                break;
            } else if (choice == '2') {
                // 退出游戏
                exit(0);
            }
        }
    }
    
    // 打印蛇的字符画
    void printSnake() {
        system("cls");
        setColor(14); // 黄色
        gotoxy(10, 5);
        cout << "    __    __    __    __";
        gotoxy(10, 6);
        cout << "   /  \\__/  \\__/  \\__/  \\";
        gotoxy(10, 7);
        cout << "  /  __    __    __    _\\";
        gotoxy(10, 8);
        cout << " /  /  \\__/  \\__/  \\__/  \\";
        gotoxy(10, 9);
        cout << "/__/    __    __    __   \\";
        gotoxy(10, 10);
        cout << "\\  \\___/  \\___/  \\___/  \\_/";
        gotoxy(10, 11);
        cout << " \\____    ____    ____   /";
        gotoxy(10, 12);
        cout << "      \\__/    \\__/    \\__/";
        setColor(7); // 恢复默认颜色
    }
    
    // 游戏说明界面
    void explanation() {
        system("cls");
        gotoxy(WIDTH / 2 - 10, 2);
        setColor(11);
        cout << "贪吃蛇游戏说明";
        setColor(7);
        
        gotoxy(5, 4);
        cout << "1. 游戏目标：控制蛇吃到食物，使蛇变得越来越长。";
        
        gotoxy(5, 6);
        cout << "2. 操作方法：";
        gotoxy(8, 7);
        cout << "- 使用方向键(↑ ↓ ← →)控制蛇的移动方向";
        gotoxy(8, 8);
        cout << "- F1键：加速";
        gotoxy(8, 9);
        cout << "- F2键：减速";
        gotoxy(8, 10);
        cout << "- ESC键：退出游戏";
        
        gotoxy(5, 12);
        cout << "3. 游戏规则：";
        gotoxy(8, 13);
        cout << "- 蛇不能撞墙";
        gotoxy(8, 14);
        cout << "- 蛇不能咬到自己";
        gotoxy(8, 15);
        cout << "- 吃到食物后，蛇身体会变长，得分增加";
        gotoxy(8, 16);
        cout << "- 加速状态下，每个食物得2分；减速状态下，每个食物得1分";
        
        gotoxy(WIDTH / 2 - 15, 19);
        cout << "按任意键返回主菜单...";
        _getch();
    }
    
    // 欢迎界面
    void welcomeToGame() {
        while (true) {
            
            gotoxy(WIDTH / 2 - 5, 15);
            cout << "贪吃蛇游戏";
            
            gotoxy(WIDTH / 2 - 10, 17);
            cout << "1. 开始游戏";
            gotoxy(WIDTH / 2 - 10, 18);
            cout << "2. 游戏说明";
            gotoxy(WIDTH / 2 - 10, 19);
            cout << "3. 退出游戏";
            
            gotoxy(WIDTH / 2 - 10, 21);
            cout << "请选择(1-3): ";
            
            char choice = _getch();
            
            if (choice == '1') {
                // 开始游戏
                gameOver = false;
                score = 0;
                sleepTime = 200;
                initSnake();
                createMap();
                scoreAndTips();
                createFood();
                drawSnake();
                return;
            } else if (choice == '2') {
                // 游戏说明
                explanation();
            } else if (choice == '3') {
                // 退出游戏
                exit(0);
            }
        }
    }
    
public:
    Game() {
        // 初始化随机数生成器
        srand(static_cast<unsigned>(time(nullptr)));
        
        // 初始化游戏状态
        gameOver = false;
        win = false;
        score = 0;
        sleepTime = 200;
        
        // 读取最高分
        File_out();
        
        // 隐藏光标
        hideCursor();
    }
    
    // 游戏主循环
    void Run() {
        // 显示欢迎界面
        welcomeToGame();
        
        while (!gameOver) {
            keyboardControl();
            snakeMove();
            
            // 检查是否撞墙或咬到自己
            if (cantCrossWall() || biteSelf()) {
                gameOver = true;
            }
            
            Sleep(sleepTime); // 控制游戏速度
        }
        
        // 游戏结束界面
        gameOverScreen();
        
        // 如果重新开始，则继续游戏循环
        if (!gameOver) {
            Run();
        }
    }
};

int main() {
    // 设置控制台标题
    SetConsoleTitle("贪吃蛇游戏");
    
    // 创建游戏对象并运行
    Game game;
    game.Run();
    
    return 0;
}
